package com.yvan.kit.image;

import org.apache.commons.io.IOUtils;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;

public final class ImageScaleUtil {

    /**
     * 缩放图片，使用Graphics2D重新绘制保存的图片，<b>注意重新绘制后丢失图片的Metadata信息</b>
     *
     * @param originalImage 原始图片文件对象
     * @param scaledImage   缩放后的图片文件对象
     * @param setWidth      缩放后的图片宽带
     * @param setHeight     缩放后的图片高度
     * @param scaleType     缩放方式类型： <br>
     *                      1 - 不留白边等比例压缩(最终的图片宽高可能会<b>比预设的尺寸小</b>) <br>
     *                      2 - 留白边等比例压缩(宽高和预设的一样，可能宽高有一边有<b>白边填充</b>) <br>
     *                      3 - 先缩等比例放或拉伸，再从中间裁剪(宽高和预设的一样，但裁剪会导致<b>图像不完整</b>) <br>
     *                      其他 - 直接按照设定的宽高填充(宽高和预设的一样，但可能会因为非等比例缩放导致<b>图片变形</b>) <br>
     */
    public static void scaleImage(File originalImage, File scaledImage, int setWidth, int setHeight, int scaleType) throws IOException {
        OutputStream outputStream = null;
        if (originalImage != null && originalImage.exists() && scaledImage != null) {
            try {
                outputStream = new BufferedOutputStream(new FileOutputStream(scaledImage));
                ImageIO.write(scaleImage(ImageIO.read(originalImage), setWidth, setHeight, scaleType), getImageFormatName(originalImage), outputStream);
            } finally {
                IOUtils.closeQuietly(outputStream);
            }
        }
    }


    /**
     * 获取图片的格式
     */
    public static String getImageFormatName(File imageFile) throws IOException {
        String imageFormatName = "";
        ImageInputStream inputStream = null;
        try {
            inputStream = ImageIO.createImageInputStream(imageFile);
            Iterator<ImageReader> iterator = ImageIO.getImageReaders(inputStream);
            if (iterator.hasNext()) {
                imageFormatName = iterator.next().getFormatName();
            }
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
        return imageFormatName;
    }

    /**
     * 缩放图片，使用Graphics2D重新绘制保存的图片，<b>注意重新绘制后丢失图片的Metadata信息</b>
     *
     * @param originalImage 原始图片对象
     * @param setWidth      缩放后的图片宽带
     * @param setHeight     缩放后的图片高度
     * @param scaleType     缩放方式类型： <br>
     *                      1 - 不留白边等比例压缩(最终的图片宽高可能会<b>比预设的尺寸小</b>) <br>
     *                      2 - 留白边等比例压缩(宽高和预设的一样，可能宽高有一边有<b>白边填充</b>) <br>
     *                      3 - 先缩等比例放或拉伸，再从中间裁剪(宽高和预设的一样，但裁剪会导致<b>图像不完整</b>) <br>
     *                      其他 - 直接按照设定的宽高填充(宽高和预设的一样，但可能会因为非等比例缩放导致<b>图片变形</b>) <br>
     */
    public static BufferedImage scaleImage(BufferedImage originalImage, int setWidth, int setHeight, int scaleType) throws IOException {
        int SCALE_ALGORITHM = Image.SCALE_SMOOTH;
        int SCALE_TYPE_RATIO = 1;
        int SCALE_TYPE_RATIO_WHITE = 2;
        int SCALE_TYPE_RATIO_CUT = 3;
        BufferedImage scaledImage = new BufferedImage(setWidth, setHeight, originalImage.getType());
        Graphics2D g2 = scaledImage.createGraphics();
        int originalWidth = originalImage.getWidth();
        int originalHeight = originalImage.getHeight();
        float originalRatio = (float) originalHeight / originalWidth;
        float setRatio = (float) setHeight / setWidth;
        if (scaleType == SCALE_TYPE_RATIO || scaleType == SCALE_TYPE_RATIO_WHITE) {
            int actualWidth = setWidth;
            int actualHeight = setHeight;
            int xCoordinate = 0;
            int yCoordinate = 0;

            /**
             * 商品图片库目前的尺寸规则为：800*800，1M以内，JPG，主图（0-1张）命名为商品编码，辅图（0-5张）命名为商品编码+下划线+数字1至5

             实际尺寸可能有800*800，480*360等。

             图片尺寸需求：

             1）商品详情页大图：800*800，图片命名为原名+_L

             2）商品列表大图：400*400，图片命名为原名+_M

             3）购物车、订单列表等缩略图：100*100，图片命名为原名+_S

             注：

             若原图片尺寸非800*800，商品图片需按原图片等比压缩（长方形压缩完还是长方形），保证原图片的MAX(长、宽)=三个尺寸对应的宽度。

             若原图片尺寸小于等于需求尺寸，对应的需求尺寸就不需要裁剪处理。

             图片处理需求：

             产品不太了解相关技术，期望：

             1.能批量把现有图片库商品图片统一处理。

             2.新图片运营人员能独立使用【界面操作】完成图片处理。
             */

            if (originalWidth >= setWidth && originalHeight < setHeight) // 宽度缩小，高度放大
            {
                actualHeight = (int) (actualWidth * originalRatio); // 等比例缩小宽度和高度至指定宽度，高度会比预设小或者存在白边
            } else if (originalWidth < setWidth && originalHeight >= setHeight) // 宽度放大，高度缩小
            {
                actualWidth = (int) (actualHeight / originalRatio); // 等比例缩小宽度和高度至指定高度，宽度会比预设小或者存在白边
            } else if (originalWidth >= setWidth && originalHeight >= setHeight) // 宽度高度都缩小
            {
                if (setRatio > originalRatio) {
                    actualHeight = (int) (actualWidth * originalRatio); // 等比例缩小宽度和高度至指定宽度，高度会比预设小或者存在白边
                } else {
                    actualWidth = (int) (actualHeight / originalRatio); // 等比例缩小宽度和高度至指定高度，宽度会比预设小或者存在白边
                }
            } else if (originalWidth < setWidth && originalHeight < setHeight) // 宽度高度都放大
            {
                if (setRatio > originalRatio) {
                    actualHeight = (int) (actualWidth * originalRatio); // 等比例放大宽度和高度至指定高度，宽度会比预设小或者存在白边
                } else {
                    actualWidth = (int) (actualHeight / originalRatio); // 等比例放大宽度和高度至指定宽度，高度会比预设小或者存在白边
                }
            }
            if (scaleType == SCALE_TYPE_RATIO) { // 不留白边等比例压缩(可能宽高有一个会比预设的尺寸小)
                scaledImage = new BufferedImage(actualWidth, actualHeight, originalImage.getType()); // 重新设定压缩后的图标大小
                g2 = scaledImage.createGraphics();
            } else if (scaleType == SCALE_TYPE_RATIO_WHITE) { // 留白边等比例压缩(宽高和预设的一样，可能宽高有一边有白边填充)
                xCoordinate = (setWidth - actualWidth) / 2;
                yCoordinate = (setHeight - actualHeight) / 2;
                // g2.setColor(new Color(0xEE, 0xEE, 0xEE));
                g2.fillRect(0, 0, setWidth, setHeight);
            }

//            g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
//            g2.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
//            g2.drawRenderedImage();

            g2.drawImage(originalImage.getScaledInstance(actualWidth, actualHeight, SCALE_ALGORITHM), xCoordinate, yCoordinate, actualWidth, actualHeight, null);
        } else if (scaleType == SCALE_TYPE_RATIO_CUT) { // 先缩等比例放或拉伸，再从中间裁剪
            int scaledWidth = setWidth;
            int scaledHeight = setHeight;
            if (originalWidth >= setWidth && originalHeight < setHeight) // 宽度缩小，高度放大
            {
                scaledWidth = (int) (setHeight * originalRatio); // 等比例放大宽度和高度至指定高度，然后再裁剪宽度
            } else if (originalWidth < setWidth && originalHeight >= setHeight) // 宽度放大，高度缩小
            {
                scaledHeight = (int) (setWidth / originalRatio); // 等比例放大宽度和高度至指定宽度，然后再裁剪高度
            } else if (originalWidth >= setWidth && originalHeight >= setHeight) // 宽度高度都缩小
            {
                if (setRatio > originalRatio) {
                    scaledWidth = (int) (setHeight / originalRatio); // 等比例缩小宽度和高度至指定高度，然后再裁剪宽度
                } else {
                    scaledHeight = (int) (setWidth * originalRatio); // 等比例缩小宽度和高度至指定宽度，然后再裁剪高度
                }
            } else if (originalWidth < setWidth && originalHeight < setHeight) // 宽度高度都放大
            {
                if (setRatio > originalRatio) {
                    scaledWidth = (int) (setHeight * originalRatio); // 等比例放大宽度和高度至指定高度，然后再裁剪宽度
                } else {
                    scaledHeight = (int) (setWidth / originalRatio); // 等比例放大宽度和高度至指定宽度，然后再裁剪高度
                }
            }
            BufferedImage tmpImage = new BufferedImage(scaledWidth, scaledHeight, originalImage.getType());
            Graphics2D tmpG2 = tmpImage.createGraphics();
            tmpG2.drawImage(originalImage.getScaledInstance(scaledWidth, scaledHeight, SCALE_ALGORITHM), 0, 0, scaledWidth, scaledHeight, null); // 等比例缩放或拉伸
            tmpG2.dispose();
            g2.drawImage(tmpImage.getSubimage((scaledWidth - setWidth) / 2, (scaledHeight - setHeight) / 2, setWidth, setHeight), 0, 0, setWidth, setHeight, null); // 从中间裁剪
        } else
        // 直接变形填充压缩(宽高和预设的一样，如果比例不对的话图片会变形)
        {
            g2.drawImage(originalImage.getScaledInstance(setWidth, setHeight, SCALE_ALGORITHM), 0, 0, setWidth, setHeight, null);
        }
        g2.dispose();
        return scaledImage;
    }


    public static void main(String args[]) throws Exception {

        File fIn = new File("/Users/huagang/Downloads/img/img/BLD019001CFY.JPG");//480*360
        File fIn1 = new File("/Users/huagang/Downloads/img/img/BLD020010C.JPG");//360*480
        File fIn2 = new File("/Users/huagang/Downloads/img/img/BLD025003C.JPG");//800*800
        File fIn3 = new File("/Users/huagang/Downloads/img/img/CAL081025G.JPG");//500*375
        File fIn4 = new File("/Users/huagang/Downloads/img/img/demo.jpg");//510*340

        File fOut_m = new File("/Users/huagang/Downloads/img/M.JPG");
        File fOut_s = new File("/Users/huagang/Downloads/img/S.JPG");
        File fOut_l = new File("/Users/huagang/Downloads/img/L.JPG");

        ImageScaleUtil.scaleImage(fIn2, fOut_m, 400, 400, 2);
        ImageScaleUtil.scaleImage(fIn2, fOut_s, 100, 100, 2);

        ImageScaleUtil.scaleImage(fIn2, fOut_l, 800, 800, 2);

    }
}
